﻿using CodeCity.AutomationMachine.DomainModels;
using Microsoft.Extensions.Hosting;
using NRules;
using NRules.Fluent;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace CodeCity.AutomationMachine
{
    public class AutomationMachineService : BackgroundService
    {
        private List<object> items = new List<object>();
        private Queue<Human> humen = new Queue<Human>();
        private IDictionary<Task, List<Human>> humenMachines = new Dictionary<Task, List<Human>>();
        private ISessionFactory factory;
        private Task environmentTask;
        private Task humanRuleTask;

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var repository = new RuleRepository();
            repository.Load(spec => spec.From(GetType().Assembly));

            factory = repository.Compile();

            environmentTask = RunEnvironmentRulesAsync();
            humanRuleTask = RunHumanRulesAsync();
            await Task.WhenAll(environmentTask, humanRuleTask);
        }

        private async Task<Task> RunEnvironmentRulesAsync()
        {
            var env = new SkyEnvironment();
            env.Temperature = 10;
            return await Task.Factory.StartNew(async () =>
            {
                while (true)
                {
                    var session = factory.CreateSession();
                    session.Insert(env);
                    session.Fire();
                    GC.Collect();
                    await Task.Delay(1000);
                }
            });
        }

        private Task RunHumanRulesAsync()
        {
            return CreateHumanMachine(0);

        }

        private Task CreateHumanMachine(int id)
        {
            var maxCount = 100;
            var created = false;
            return Task.Factory.StartNew(async () =>
            {
                var currentHumen = new List<Human>();
                while (true)
                {
                    var session = factory.CreateSession();
                    if (!created && humen.Any())
                    {
                        if (currentHumen.Count < maxCount)
                        {
                            ReceiveHumen(maxCount, currentHumen);
                        }
                        else
                        {
                            created = true;
                            _ = CreateHumanMachine(id++);
                        }
                    }
                    session.InsertAll(currentHumen);
                    session.Fire();
                    Log.Information($"【{{Rule}}】{id}号自动机完成一个循环，人数：{currentHumen.Count}", "Human");
                    await Task.Delay(1000);
                }
            }, TaskCreationOptions.LongRunning);
        }

        private void ReceiveHumen(int maxCount, List<Human> currentHumen)
        {
            while (currentHumen.Count < maxCount)
            {
                currentHumen.Add(humen.Dequeue());
                if (!humen.Any())
                {
                    break;
                }
            }
        }

        //private Task RunAutomationMachine()
        //{
        //    return Task.Factory.StartNew(() =>
        //    {
        //        session.Fire();
        //    });
        //}

        public void AddObject(Human item)
        {
            item.GrowSpeed = 1;
            humen.Enqueue(item);
        }
    }
}
